package admin

import (
	"context"
	"encoding/json"
	"fmt"
	io "io/ioutil"
	"time"

	"open/pkg/middleware/auth"

	"open/pkg/bytedance"

	"github.com/go-kratos/kratos/v2/errors"
	"gorm.io/gorm"

	v1 "open/api/open/admin/v1"
	"open/internal/model"
	"open/internal/model/event"
	"open/internal/model/field"
	"open/internal/types"
)

// GetBytedancePreAuthCode 获取字节跳动预授权码
func (s *Service) GetBytedancePreAuthCode(ctx context.Context, _ *v1.GetBytedancePreAuthCodeRequest) (*v1.GetBytedancePreAuthCodeReply, error) {
	return s.dao.GetBytedancePreAuthCode(ctx)
}

// AuthorizeBytedance 授权字节跳动应用
func (s *Service) AuthorizeBytedance(ctx context.Context, req *v1.BytedanceAuthorizeRequest) (*v1.BytedanceAuthorizeReply, error) {
	authAppID, err := s.dao.AuthorizeBytedance(ctx, req.AuthorizationCode, req.ExpiresIn)
	if err != nil {
		return nil, err
	}
	// 查询信息
	authAppInfo, err := s.dao.GetBytedanceAppInfo(ctx, authAppID)
	if err != nil {
		return nil, err
	}
	user, err := auth.FromContext(ctx)
	if err != nil {
		return nil, err
	}
	err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		// 删除现存跟小程序的关联关系
		if err := s.dao.BrandMiniAppRef(ctx, user.BrandID, authAppID, types.ByteDance); err != nil {
			return err
		}
		// 落库品牌跟小程序关联关系
		if err := s.dao.CreateBrandMiniAppRef(ctx, &model.BrandMiniApp{
			Platform: types.ByteDance,
			BrandID:  user.BrandID,
			AppID:    authAppID,
			EmpID:    user.EmpID,
		}); err != nil {
			return err
		}
		// 落库小程序应用信息
		bytedanceMiniApp, err := s.dao.GetOrCreateBytedanceMiniApp(ctx, authAppID)
		if err != nil {
			return err
		}
		bytedanceMiniApp.Name = authAppInfo.AppName
		bytedanceMiniApp.Icon = authAppInfo.AppIcon
		bytedanceMiniApp.AppID = authAppInfo.AppID
		bytedanceMiniApp.Intro = authAppInfo.AppIntro

		if err := s.dao.SaveBytedanceMiniApp(ctx, bytedanceMiniApp); err != nil {
			return err
		}
		// 初始化版本信息
		if err := s.dao.CreateAppVersion(ctx, &model.MiniAppVersion{
			Platform: types.ByteDance,
			AppID:    authAppID,
			Status:   types.StatusAuthorized,
			Stage:    types.StageInitialized,
		}); err != nil {
			return err
		}
		// 发送应用创建事件
		return s.dao.TxSend(ctx, &event.BytedanceMiniAppCreated{
			AppID:     authAppID,
			Timestamp: time.Now().Unix(),
		})
	})
	if err != nil {
		return nil, err
	}
	return &v1.BytedanceAuthorizeReply{Message: "ok"}, nil
}

// GetBytedanceMini 获取字节跳动小程序信息
func (s *Service) GetBytedanceMini(ctx context.Context, req *v1.GetBytedanceMiniRequest) (*v1.GetBytedanceMiniReply, error) {
	user, err := auth.FromContext(ctx)
	if err != nil {
		return nil, err
	}
	appID, err := s.dao.GetAppIDByBrandID(ctx, user.BrandID, types.ByteDance)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.BadRequest(v1.ErrorCode_AUTH_NOT_FOUND.String(), "字节跳动小程序未授权")
		}
		return nil, err
	}
	subApp, err := s.dao.GetBytedanceSubApp(ctx, appID)
	if err != nil {
		return nil, err
	}
	if subApp.Status == types.BytedanceAuthUnauthorized {
		return nil, errors.Unauthorized(
			v1.ErrorCode_AUTH_UNAUTHORIZED.String(),
			"应用未授权或者商家主动取消授权,请重新授权后重试！")
	}
	bytedanceMiniApp, err := s.dao.GetBytedanceMiniApp(ctx, appID)
	if err != nil {
		return nil, err
	}
	appVersion, err := s.dao.GetAppVersion(ctx, appID, types.ByteDance)
	if err != nil {
		return nil, err
	}
	return &v1.GetBytedanceMiniReply{
		AppId:     bytedanceMiniApp.AppID,
		Name:      bytedanceMiniApp.Name,
		Icon:      bytedanceMiniApp.Icon,
		Intro:     bytedanceMiniApp.Intro,
		QrCodeUrl: bytedanceMiniApp.QrCodeURL,
		Version: &v1.GetBytedanceMiniReply_Version{
			ReleaseVersion: appVersion.ReleaseVersion,
			Status:         appVersion.Status,
			AuditVersion:   appVersion.AuditVersion,
			RejectReason:   appVersion.RejectReason,
			UpdateTime:     appVersion.UpdatedAt.Format("2006-01-02 15:04:05"),
		},
	}, nil
}

// CommitBytedanceMini 提交字节跳动小程序
func (s *Service) CommitBytedanceMini(ctx context.Context, _ *v1.CommitBytedanceMiniRequest) (*v1.CommitBytedanceMiniReply, error) {
	user, err := auth.FromContext(ctx)
	if err != nil {
		return nil, err
	}
	appID, err := s.dao.GetAppIDByBrandID(ctx, user.BrandID, types.ByteDance)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.BadRequest(v1.ErrorCode_AUTH_NOT_FOUND.String(), "字节跳动小程序未授权")
		}
		return nil, err
	}

	if err = s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.ByteDance)
		if err != nil {
			return err
		}
		appVersion.Stage = types.StageInitialized
		appVersion.Status = types.StatusAuditing
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		template, err := s.dao.GetLatestBytedanceTemplate(ctx)
		if err != nil {
			return err
		}

		ext := fmt.Sprintf(`{"brand_id": %d, "app_id": "%s"}`, user.BrandID, appID)
		commitTemplate := template.ToVO(fmt.Sprintf(`{"extAppid": "%s", "ext": %s}`, appVersion.AppID, ext))
		jobData, _ := json.Marshal(commitTemplate)
		schedule := &model.Schedule{
			JobType:   types.TaskCommitCode,
			RefID:     appVersion.ID,
			JobData:   field.JSON(jobData),
			JobStatus: types.ScheduleTaskInit,
		}
		if err = s.dao.CreateSchedule(ctx, schedule); err != nil {
			return err
		}
		// 发送事件
		if err = s.dao.TxSend(ctx, event.TaskCommitCode{
			AppID:     appVersion.AppID,
			Platform:  appVersion.Platform,
			Biz:       jobData,
			Timestamp: time.Now().Unix(),
		}); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return nil, err
	}
	return &v1.CommitBytedanceMiniReply{Message: "ok"}, nil
}

// GetBytedanceMiniTestQRCode 获取字节跳动小程序体验码
func (s *Service) GetBytedanceMiniTestQRCode(ctx context.Context, _ *v1.GetBytedanceMiniTestQRCodeRequest) (*v1.GetBytedanceMiniTestQRCodeReply, error) {
	user, err := auth.FromContext(ctx)
	if err != nil {
		return nil, err
	}
	appID, err := s.dao.GetAppIDByBrandID(ctx, user.BrandID, types.ByteDance)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.BadRequest(v1.ErrorCode_AUTH_NOT_FOUND.String(), "字节跳动小程序未授权")
		}
		return nil, err
	}
	appVersion, err := s.dao.GetAppVersion(ctx, appID, types.ByteDance)
	if err != nil {
		return nil, err
	}
	var version string
	switch appVersion.Stage {
	case types.StageCommitted, types.StageAuditReject:
		version = "latest"
	case types.StatusAuditing, types.StageWaitRelease:
		version = "audit"
	default:
		return nil, errors.BadRequest("APP_NOT_FOUND", "暂无体验版")
	}
	resp, err := s.dao.GetBytedanceMiniTestQRCode(ctx, appID, version)
	if err != nil {
		if bytedanceError, ok := err.(*bytedance.ErrorResponse); ok {
			return nil, errors.BadRequest("BYTEDANCE_ERROR", bytedanceError.Message)
		}
		return nil, err
	}
	defer resp.Body.Close()

	content, _ := io.ReadAll(resp.Body)
	return &v1.GetBytedanceMiniTestQRCodeReply{
		Content:       content,
		ContentLength: resp.ContentLength,
		ContentType:   resp.Header.Get("Content-Type"),
	}, nil
}

// CreateBytedanceMiniQRCode 创建字节跳动小程序二维码
func (s *Service) CreateBytedanceMiniQRCode(ctx context.Context, req *v1.CreateBytedanceMiniQRCodeRequest) (*v1.CreateBytedanceMiniQRCodeReply, error) {
	user, err := auth.FromContext(ctx)
	if err != nil {
		return nil, err
	}
	appID, err := s.dao.GetAppIDByBrandID(ctx, user.BrandID, types.ByteDance)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.BadRequest(v1.ErrorCode_AUTH_NOT_FOUND.String(), "字节跳动小程序未授权")
		}
		return nil, err
	}

	resp, err := s.dao.CreateBytedanceMiniQRCode(ctx, appID, req)
	if err != nil {
		if bytedanceError, ok := err.(*bytedance.ErrorResponse); ok {
			return nil, errors.BadRequest("BYTEDANCE_ERROR", bytedanceError.Message)
		}
		return nil, err
	}
	defer resp.Body.Close()
	content, _ := io.ReadAll(resp.Body)
	return &v1.CreateBytedanceMiniQRCodeReply{
		Content:       content,
		ContentLength: resp.ContentLength,
		ContentType:   resp.Header.Get("Content-Type"),
	}, nil
}
